/*
* Copyright (c) Microsoft Corporation.  All Rights Reserved.
*
* Helper class for working with class method detour Prototypes
*/
#pragma once
#include "Mock10.h"
#include "ParameterTypes.h"

#pragma push_macro("SEALED")
#undef SEALED

#if _MSC_VER >= 1400
# define SEALED sealed
#else
# define SEALED
#endif

namespace Mock10 { namespace Private
{
    #define DETOUR_METHOD_NAMED_ARGS_0 
    #define DETOUR_METHOD_NAMED_ARGS_1 , typename TParameterTypes::Parameter1 p1
    #define DETOUR_METHOD_NAMED_ARGS_2 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2
    #define DETOUR_METHOD_NAMED_ARGS_3 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3
    #define DETOUR_METHOD_NAMED_ARGS_4 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4
    #define DETOUR_METHOD_NAMED_ARGS_5 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5
    #define DETOUR_METHOD_NAMED_ARGS_6 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5, typename TParameterTypes::Parameter6 p6
    #define DETOUR_METHOD_NAMED_ARGS_7 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5, typename TParameterTypes::Parameter6 p6, typename TParameterTypes::Parameter7 p7
    #define DETOUR_METHOD_NAMED_ARGS_8 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5, typename TParameterTypes::Parameter6 p6, typename TParameterTypes::Parameter7 p7, typename TParameterTypes::Parameter8 p8
    #define DETOUR_METHOD_NAMED_ARGS_9 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5, typename TParameterTypes::Parameter6 p6, typename TParameterTypes::Parameter7 p7, typename TParameterTypes::Parameter8 p8, typename TParameterTypes::Parameter9 p9
    #define DETOUR_METHOD_NAMED_ARGS_10 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5, typename TParameterTypes::Parameter6 p6, typename TParameterTypes::Parameter7 p7, typename TParameterTypes::Parameter8 p8, typename TParameterTypes::Parameter9 p9, typename TParameterTypes::Parameter10 p10
    #define DETOUR_METHOD_NAMED_ARGS_11 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5, typename TParameterTypes::Parameter6 p6, typename TParameterTypes::Parameter7 p7, typename TParameterTypes::Parameter8 p8, typename TParameterTypes::Parameter9 p9, typename TParameterTypes::Parameter10 p10, typename TParameterTypes::Parameter11 p11
    #define DETOUR_METHOD_NAMED_ARGS_12 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5, typename TParameterTypes::Parameter6 p6, typename TParameterTypes::Parameter7 p7, typename TParameterTypes::Parameter8 p8, typename TParameterTypes::Parameter9 p9, typename TParameterTypes::Parameter10 p10, typename TParameterTypes::Parameter11 p11, typename TParameterTypes::Parameter12 p12
    #define DETOUR_METHOD_NAMED_ARGS_13 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5, typename TParameterTypes::Parameter6 p6, typename TParameterTypes::Parameter7 p7, typename TParameterTypes::Parameter8 p8, typename TParameterTypes::Parameter9 p9, typename TParameterTypes::Parameter10 p10, typename TParameterTypes::Parameter11 p11, typename TParameterTypes::Parameter12 p12, typename TParameterTypes::Parameter13 p13
    #define DETOUR_METHOD_NAMED_ARGS_14 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5, typename TParameterTypes::Parameter6 p6, typename TParameterTypes::Parameter7 p7, typename TParameterTypes::Parameter8 p8, typename TParameterTypes::Parameter9 p9, typename TParameterTypes::Parameter10 p10, typename TParameterTypes::Parameter11 p11, typename TParameterTypes::Parameter12 p12, typename TParameterTypes::Parameter13 p13, typename TParameterTypes::Parameter14 p14
    #define DETOUR_METHOD_NAMED_ARGS_15 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5, typename TParameterTypes::Parameter6 p6, typename TParameterTypes::Parameter7 p7, typename TParameterTypes::Parameter8 p8, typename TParameterTypes::Parameter9 p9, typename TParameterTypes::Parameter10 p10, typename TParameterTypes::Parameter11 p11, typename TParameterTypes::Parameter12 p12, typename TParameterTypes::Parameter13 p13, typename TParameterTypes::Parameter14 p14, typename TParameterTypes::Parameter15 p15
    #define DETOUR_METHOD_NAMED_ARGS_16 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5, typename TParameterTypes::Parameter6 p6, typename TParameterTypes::Parameter7 p7, typename TParameterTypes::Parameter8 p8, typename TParameterTypes::Parameter9 p9, typename TParameterTypes::Parameter10 p10, typename TParameterTypes::Parameter11 p11, typename TParameterTypes::Parameter12 p12, typename TParameterTypes::Parameter13 p13, typename TParameterTypes::Parameter14 p14, typename TParameterTypes::Parameter15 p15, typename TParameterTypes::Parameter16 p16
    #define DETOUR_METHOD_NAMED_ARGS_17 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5, typename TParameterTypes::Parameter6 p6, typename TParameterTypes::Parameter7 p7, typename TParameterTypes::Parameter8 p8, typename TParameterTypes::Parameter9 p9, typename TParameterTypes::Parameter10 p10, typename TParameterTypes::Parameter11 p11, typename TParameterTypes::Parameter12 p12, typename TParameterTypes::Parameter13 p13, typename TParameterTypes::Parameter14 p14, typename TParameterTypes::Parameter15 p15, typename TParameterTypes::Parameter16 p16, typename TParameterTypes::Parameter17 p17
    #define DETOUR_METHOD_NAMED_ARGS_18 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5, typename TParameterTypes::Parameter6 p6, typename TParameterTypes::Parameter7 p7, typename TParameterTypes::Parameter8 p8, typename TParameterTypes::Parameter9 p9, typename TParameterTypes::Parameter10 p10, typename TParameterTypes::Parameter11 p11, typename TParameterTypes::Parameter12 p12, typename TParameterTypes::Parameter13 p13, typename TParameterTypes::Parameter14 p14, typename TParameterTypes::Parameter15 p15, typename TParameterTypes::Parameter16 p16, typename TParameterTypes::Parameter17 p17, typename TParameterTypes::Parameter18 p18
    #define DETOUR_METHOD_NAMED_ARGS_19 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5, typename TParameterTypes::Parameter6 p6, typename TParameterTypes::Parameter7 p7, typename TParameterTypes::Parameter8 p8, typename TParameterTypes::Parameter9 p9, typename TParameterTypes::Parameter10 p10, typename TParameterTypes::Parameter11 p11, typename TParameterTypes::Parameter12 p12, typename TParameterTypes::Parameter13 p13, typename TParameterTypes::Parameter14 p14, typename TParameterTypes::Parameter15 p15, typename TParameterTypes::Parameter16 p16, typename TParameterTypes::Parameter17 p17, typename TParameterTypes::Parameter18 p18, typename TParameterTypes::Parameter19 p19
    #define DETOUR_METHOD_NAMED_ARGS_20 , typename TParameterTypes::Parameter1 p1, typename TParameterTypes::Parameter2 p2, typename TParameterTypes::Parameter3 p3, typename TParameterTypes::Parameter4 p4, typename TParameterTypes::Parameter5 p5, typename TParameterTypes::Parameter6 p6, typename TParameterTypes::Parameter7 p7, typename TParameterTypes::Parameter8 p8, typename TParameterTypes::Parameter9 p9, typename TParameterTypes::Parameter10 p10, typename TParameterTypes::Parameter11 p11, typename TParameterTypes::Parameter12 p12, typename TParameterTypes::Parameter13 p13, typename TParameterTypes::Parameter14 p14, typename TParameterTypes::Parameter15 p15, typename TParameterTypes::Parameter16 p16, typename TParameterTypes::Parameter17 p17, typename TParameterTypes::Parameter18 p18, typename TParameterTypes::Parameter19 p19, typename TParameterTypes::Parameter20 p20

    #define DETOUR_METHOD_ARGS_0 
    #define DETOUR_METHOD_ARGS_1 , p1
    #define DETOUR_METHOD_ARGS_2 , p1, p2
    #define DETOUR_METHOD_ARGS_3 , p1, p2, p3
    #define DETOUR_METHOD_ARGS_4 , p1, p2, p3, p4
    #define DETOUR_METHOD_ARGS_5 , p1, p2, p3, p4, p5
    #define DETOUR_METHOD_ARGS_6 , p1, p2, p3, p4, p5, p6
    #define DETOUR_METHOD_ARGS_7 , p1, p2, p3, p4, p5, p6, p7
    #define DETOUR_METHOD_ARGS_8 , p1, p2, p3, p4, p5, p6, p7, p8
    #define DETOUR_METHOD_ARGS_9 , p1, p2, p3, p4, p5, p6, p7, p8, p9
    #define DETOUR_METHOD_ARGS_10 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10
    #define DETOUR_METHOD_ARGS_11 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11
    #define DETOUR_METHOD_ARGS_12 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12
    #define DETOUR_METHOD_ARGS_13 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13
    #define DETOUR_METHOD_ARGS_14 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14
    #define DETOUR_METHOD_ARGS_15 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15
    #define DETOUR_METHOD_ARGS_16 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16
    #define DETOUR_METHOD_ARGS_17 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17
    #define DETOUR_METHOD_ARGS_18 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18
    #define DETOUR_METHOD_ARGS_19 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19
    #define DETOUR_METHOD_ARGS_20 , p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20

    template <typename TParameterTypes, unsigned short ParameterCount, bool isConst>
    struct DetourMethodImpl;
    
    #define DETOUR_METHOD_IMPL(PARAMCOUNT)                                                                                                                                      \
    template <typename TPrototype>                                                                                                                                              \
    struct DetourMethodImpl<TPrototype, PARAMCOUNT, false>                                                                                                                      \
    {                                                                                                                                                                           \
    public:                                                                                                                                                                     \
        typedef typename WEX::Common::ParameterTypes<TPrototype> TParameterTypes;                                                                                               \
        typedef typename TParameterTypes::ReturnType (Prototype) (typename TParameterTypes::ClassType& BUILD_VARIABLE_NAME(DETOUR_METHOD_NAMED_ARGS_, PARAMCOUNT));             \
    };                                                                                                                                                                          \
                                                                                                                                                                                \
    template <typename TPrototype>                                                                                                                                              \
    struct DetourMethodImpl<TPrototype, PARAMCOUNT, true>                                                                                                                       \
    {                                                                                                                                                                           \
    public:                                                                                                                                                                     \
        typedef typename WEX::Common::ParameterTypes<TPrototype> TParameterTypes;                                                                                               \
        typedef typename TParameterTypes::ReturnType (Prototype) (typename const TParameterTypes::ClassType& BUILD_VARIABLE_NAME(DETOUR_METHOD_NAMED_ARGS_, PARAMCOUNT));       \
    }                                                                                                                                                                           \

    DETOUR_METHOD_IMPL(0);
    DETOUR_METHOD_IMPL(1);
    DETOUR_METHOD_IMPL(2);
    DETOUR_METHOD_IMPL(3);
    DETOUR_METHOD_IMPL(4);
    DETOUR_METHOD_IMPL(5);
    DETOUR_METHOD_IMPL(6);
    DETOUR_METHOD_IMPL(7);
    DETOUR_METHOD_IMPL(8);
    DETOUR_METHOD_IMPL(9);
    DETOUR_METHOD_IMPL(10);
    DETOUR_METHOD_IMPL(11);
    DETOUR_METHOD_IMPL(12);
    DETOUR_METHOD_IMPL(13);
    DETOUR_METHOD_IMPL(14);
    DETOUR_METHOD_IMPL(15);
    DETOUR_METHOD_IMPL(16);
    DETOUR_METHOD_IMPL(17);
    DETOUR_METHOD_IMPL(18);
    DETOUR_METHOD_IMPL(19);
    DETOUR_METHOD_IMPL(20);

    template <typename TPrototype>
    struct DetourMethod SEALED : public DetourMethodImpl<TPrototype, WEX::Common::ParameterTypes<TPrototype>::ParameterCount, WEX::Common::ParameterTypes<TPrototype>::IsConstMethod>
    {
    };
} /* namespace Private */ } /* namespace Mock10 */

#pragma pop_macro("SEALED")